import json
from django.views import View
from apps.users.models import User, Address
from django.http import JsonResponse, HttpResponseBadRequest
from django.contrib.auth import login, logout, authenticate
import re
import logging
from django.conf import settings

logger = logging.getLogger('django')


# Create your views here.
class UsernameCountView(View):
    def get(self, request, username):
        count = User.objects.filter(username=username).count()
        return JsonResponse({
            "code": 0,
            "count": count,
            "errmsg": "ok"
        },
            json_dumps_params={"ensure_ascii": False})


class MobileCountView(View):
    def get(self, request, mobile):
        count = User.objects.filter(mobile=mobile).count()
        return JsonResponse({
            "code": 0,
            "count": count,
            "errmsg": "ok"
        },
            json_dumps_params={"ensure_ascii": False})


class RegisterView(View):
    """用户注册"""

    def post(self, request):
        """
        实现用户注册
        :param request: 请求对象
        :return: 注册结果
        """
        import json
        # 1.接收参数：请求体中的JSON数据 request.body
        json_bytes = request.body  # 从请求体中获取原始的JSON数据，bytes类型的
        json_str = json_bytes.decode()  # 将bytes类型的JSON数据，转成JSON字符串
        json_dict = json.loads(json_str)  # 将JSON字符串，转成python的标准字典
        # json_dict = json.loads(request.body.decode())

        # 提取参数
        username = json_dict.get('username')
        password = json_dict.get('password')
        password2 = json_dict.get('password2')
        mobile = json_dict.get('mobile')
        allow = json_dict.get('allow')
        sms_code = json_dict.get('sms_code')

        # 判断参数是否齐全
        if not all([username, password, password2, mobile, allow]):
            return JsonResponse({'code': 400, 'errmsg': '缺少必传参数!'},
                                json_dumps_params={"ensure_ascii": False})
        # 判断用户名是否是5-20个字符
        if not re.match(r'^[a-zA-Z0-9_]{5,20}$', username):
            return JsonResponse({'code': 400, 'errmsg': 'username格式有误!'},
                                json_dumps_params={"ensure_ascii": False})
        # 判断密码是否是8-20个数字
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return JsonResponse({'code': 400, 'errmsg': 'password格式有误!'},
                                json_dumps_params={"ensure_ascii": False})
        # 判断两次密码是否一致
        if password != password2:
            return JsonResponse({'code': 400, 'errmsg': '两次输入不对!'},
                                json_dumps_params={"ensure_ascii": False})
        # 判断手机号是否合法
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400, 'errmsg': 'mobile格式有误!'},
                                json_dumps_params={"ensure_ascii": False})
        # 判断是否勾选用户协议
        if not allow:
            return JsonResponse({'code': 400, 'errmsg': 'allow格式有误!'},
                                json_dumps_params={"ensure_ascii": False})
        try:
            # create_user()方法中封装了set_password()方法加密密码
            user = User.objects.create_user(username=username,
                                            password=password,
                                            mobile=mobile)
        except Exception as e:
            return JsonResponse({'code': 400, 'errmsg': '注册失败!'},
                                json_dumps_params={"ensure_ascii": False})
        # Django提供了状态保持的方法
        login(request, user)
        return JsonResponse({'code': 0, 'errmsg': '注册成功!'},
                            json_dumps_params={"ensure_ascii": False})


class LoginView(View):
    def post(self, request):
        dict = json.loads(request.body.decode())
        username = dict.get('username')
        password = dict.get('password')
        remembered = dict.get('remembered')

        # 2.校验(整体 + 单个)
        if not all([username, password]):
            return JsonResponse({'code': 400,
                                 'errmsg': '缺少必传参数'},
                                json_dumps_params={"ensure_ascii": False})
        # 修改 USERNAME_FIELD 来影响 authenticate 的查询
        import re
        if re.match('1[3-9]\d{9}', username):
            # 手机号
            User.USERNAME_FIELD = 'mobile'
        else:
            # account 是用户名
            # 根据用户名从数据库获取 user 对象返回.
            User.USERNAME_FIELD = 'username'
        # 3.验证是否能够登录
        user = authenticate(username=username,
                            password=password)

        # 判断是否为空,如果为空,返回
        if user is None:
            return JsonResponse({'code': 400,
                                 'errmsg': '用户名或者密码错误'},
                                json_dumps_params={"ensure_ascii": False})

        # 4.状态保持
        login(request, user)

        # 5.判断是否记住用户
        if not remembered:
            # 7.如果没有记住: 关闭立刻失效
            request.session.set_expiry(0)
        else:
            # 6.如果记住:  设置为两周有效，默认为两周
            request.session.set_expiry(None)

        # 8.返回json
        response = JsonResponse({'code': 0,
                                 'errmsg': 'ok'},
                                json_dumps_params={"ensure_ascii": False})
        # 注册时用户名写入到cookie，有效期15天
        response.set_cookie('username', user.username, max_age=3600 * 24 * 15)

        return response


class LogoutView(View):
    """退出登录"""

    def delete(self, request):
        """实现退出登录逻辑"""
        # 清理session
        logout(request)
        # 退出登录，重定向到登录页
        response = JsonResponse({'code': 0,
                                 'errmsg': 'ok'},
                                json_dumps_params={"ensure_ascii": False})
        # 退出登录时清除cookie中的username
        response.delete_cookie('username')

        return response


# class UserInfoView(LoginRequiredMixin, View):
#     """用户中心"""
#
#     def get(self, request):
#         """提供个人信息界面"""
#         return JsonResponse({
#             'code': 0,
#             'errmsg': '个人中心',
#             "info_data": {
#                 "username": "itcast",
#                 "mobile": "18310820688",
#                 "email": "",
#                 "email_active": 'true'
#             }
#         })


from utils.views import LoginRequiredJSONMixin


class UserInfoView(LoginRequiredJSONMixin, View):
    def get(self, request):
        """提供个人信息界面"""

        # 获取界面需要的数据,进行拼接
        info_data = {
            'username': request.user.username,
            'mobile': request.user.mobile,
            'email': request.user.email,
            'email_active': request.user.email_active
        }

        # 返回响应
        return JsonResponse({'code': 0,
                             'errmsg': 'ok',
                             'info_data': info_data},
                            json_dumps_params={"ensure_ascii": False})

    """添加邮箱"""

    def put(self, request):
        """实现添加邮箱逻辑"""
        # 判断用户是否登录并返回JSON
        pass


class EmailView(View):
    """添加邮箱"""

    def put(self, request):
        """实现添加邮箱逻辑"""
        # 接收参数
        json_dict = json.loads(request.body.decode())
        email = json_dict.get('email')

        # 校验参数
        if not email:
            return JsonResponse({'code': 400,
                                 'errmsg': '缺少email参数'},
                                json_dumps_params={"ensure_ascii": False})
        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return JsonResponse({'code': 400,
                                 'errmsg': '参数email有误'},
                                json_dumps_params={"ensure_ascii": False})

            # 赋值email字段
        try:
            request.user.email = email
            request.user.save()


        except Exception as e:
            logger.error(e)
            return JsonResponse({'code': 400, 'errmsg': '添加邮箱失败'},
                                json_dumps_params={"ensure_ascii": False})

            # 4. 发送一封激活邮件
            # 一会单独讲发送邮件
            from django.core.mail import send_mail
            # subject, message, from_email, recipient_list,
            # subject,      主题
            subject = '美多商城激活邮件'
            # message,      邮件内容
            message = ""
            # from_email,   发件人
            from_email = '美多商城<qi_rui_hua@163.com>'
            # recipient_list, 收件人列表
            recipient_list = ['qi_rui_hua@126.com', 'qi_rui_hua@163.com']

            # 邮件的内容如果是 html 这个时候使用 html_message
            # 4.1 对a标签的连接数据进行加密处理
            # user_id=1
            from apps.users.utils import generic_email_verify_token
            token = generic_email_verify_token(request.user.id)

            verify_url = "http://www.meiduo.site:8080/success_verify_email.html?token=%s" % token
            # 4.2 组织我们的激活邮件
            html_message = '<p>尊敬的用户您好！</p>' \
                           '<p>感谢您使用美多商城。</p>' \
                           '<p>您的邮箱为：%s 。请点击此链接激活您的邮箱：</p>' \
                           '<p><a href="%s">%s<a></p>' % (email, verify_url, verify_url)

            # html_message="点击按钮进行激活 <a href='http://www.itcast.cn/?token=%s'>激活</a>"%token

            # send_mail(subject=subject,
            #           message=message,
            #           from_email=from_email,
            #           recipient_list=recipient_list,
            #           html_message=html_message)
            from celery_tasks.email.tasks import celery_send_verify_email
            celery_send_verify_email.delay(
                subject=subject,
                message=message,
                from_email=from_email,
                recipient_list=recipient_list,
                html_message=html_message
            )

        # 响应添加邮箱结果
        return JsonResponse({'code': 0, 'errmsg': '添加邮箱成功'},
                            json_dumps_params={"ensure_ascii": False})


class EmailVerifyView(View):

    def put(self, request):
        # 1. 接收请求
        params = request.GET
        # 2. 获取参数
        token = params.get('token')
        # 3. 验证参数
        if token is None:
            return JsonResponse({'code': 400, 'errmsg': '参数缺失'},
                                json_dumps_params={"ensure_ascii": False})
        # 4. 获取user_id
        from apps.users.utils import check_verify_token
        user_id = check_verify_token(token)
        if user_id is None:
            return JsonResponse({'code': 400, 'errmsg': '参数错误'},
                                json_dumps_params={"ensure_ascii": False})
        # 5. 根据用户id查询数据
        user = User.objects.get(id=user_id)
        # 6. 修改数据
        user.email_active = True
        user.save()
        # 7. 返回响应JSON
        return JsonResponse({'code': 0, 'errmsg': 'ok'},
                            json_dumps_params={"ensure_ascii": False})


from utils.views import LoginRequiredJSONMixin


class ChangePasswordView(LoginRequiredJSONMixin, View):
    """修改密码"""

    def put(self, request):
        """实现修改密码逻辑"""
        # 接收参数
        dict = json.loads(request.body.decode())
        old_password = dict.get('old_password')
        new_password = dict.get('new_password')
        new_password2 = dict.get('new_password2')

        # 校验参数
        if not all([old_password, new_password, new_password2]):
            return JsonResponse({'code': 400,
                                 'errmsg': '缺少必传参数'},
                                json_dumps_params={"ensure_ascii": False})

        result = request.user.check_password(old_password)
        if not result:
            return JsonResponse({'code': 400,
                                 'errmsg': '原始密码不正确'},
                                json_dumps_params={"ensure_ascii": False})

        if not re.match(r'^[0-9A-Za-z]{8,20}$', new_password):
            return JsonResponse({'code': 400,
                                 'errmsg': '密码最少8位,最长20位'})

        if new_password != new_password2:
            return JsonResponse({'code': 400,
                                 'errmsg': '两次输入密码不一致'},
                                json_dumps_params={"ensure_ascii": False})

        # 修改密码
        try:
            request.user.set_password(new_password)
            request.user.save()
        except Exception as e:

            return JsonResponse({'code': 400,
                                 'errmsg': '修改密码失败'},
                                json_dumps_params={"ensure_ascii": False})

        # 清理状态保持信息
        logout(request)

        response = JsonResponse({'code': 0,
                                 'errmsg': 'ok'},
                                json_dumps_params={"ensure_ascii": False})

        response.delete_cookie('username')

        # # 响应密码修改结果：重定向到登录界面
        return response


class CreateAddressView(LoginRequiredJSONMixin, View):
    """新增地址"""

    def post(self, request):
        """实现新增地址逻辑"""
        # 判断是否超过地址上限：最多20个
        # Address.objects.filter(user=request.user).count()
        count = request.user.addresses.count()
        if count >= settings.USER_ADDRESS_COUNTS_LIMIT:
            return JsonResponse({'code': 400, 'errmsg': '超过地址数量上限'})

        # 接收参数
        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        # 校验参数
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return HttpResponseBadRequest('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return HttpResponseBadRequest('参数mobile有误')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return HttpResponseBadRequest('参数tel有误')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return HttpResponseBadRequest('参数email有误')

        # 保存地址信息
        try:
            address = Address.objects.create(
                user=request.user,
                title=receiver,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email
            )

            # 设置默认地址
            if not request.user.default_address:
                request.user.default_address = address
                request.user.save()
        except Exception as e:
            logger.error(e)
            return JsonResponse({'code': 400, 'errmsg': '新增地址失败'})

        # 新增地址成功，将新增的地址响应给前端实现局部刷新
        address_dict = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }

        # 响应保存结果
        return JsonResponse({'code': 0, 'errmsg': '新增地址成功', 'address': address_dict})
